/**
 * Created by jinxs on 14-8-7.
 */
(function ($) {
    /**
     * 缓存名称
     * @type {string}
     * @private
     */
    var _cacheName = 'uiAccordion';
    /**
     * @class 手风琴选项卡
     * @requires {@link uiPanel}
     * @constructor uiAccordion
     * @summary 构造函数
     * @param [options] {Object|String} 组件配置参数|要调用的组件方法名
     * @param [param] {Object} 表示要调用的组件方法的参数
     * @example
     * // 构件组件
     * $('#divMenu').uiAccordion({width: 160, height: 500});
     * // 调用组件方法options
     * $('#divMenu').uiAccordion("options");
     */
    $.fn.uiAccordion = function (options, param) {
        if (typeof options == 'string') {
            return $.fn.uiAccordion.methods[options](this, param);
        }
        return this.each(function(){
            var me = $(this);
            var cache = me.data(_cacheName);

            options = options || {};
            if (cache) {
                $.extend(cache.options, options);
            } else {
                me.data(_cacheName, {
                    options: $.extend({}, $.fn.uiAccordion.defaults, me.parseUIConfig(), options)
                });
                _setProperties(me);
                _init(me);
            }
            _setSize(me);
            _doFirstSelect(me);
        });
    };

    /**
     * 方法
     * @lends uiAccordion.prototype
     */
    $.fn.uiAccordion.methods = {
        /**
         * @summary 获得组件的配置对象
         * @name uiAccordion#options
         * @function
         * @returns {Object} 组件的配置对象
         */
        options: function (target) {
            return $.data(target[0], _cacheName).options;
        },
        /**
         * @summary 获得组件的面板对象列表
         * @name uiAccordion#panels
         * @function
         * @returns {Array<uiPanel>} 组件的面板对象列表
         */
        panels: function (target) {
            return $.data(target[0], _cacheName).panels;
        },
        /**
         * @summary 根据配置重置控件的大小
         * @name uiAccordion#resize
         * @function
         * @returns {jQuery} 方法调用者
         */
        resize: function (target) {
            _setSize(target);
            return target;
        },
        /**
         * @summary 获得选择的面板对象列表
         * @name uiAccordion#getSelections
         * @function
         * @returns {Array<uiPanel>} 获得选择的面板对象列表
         */
        getSelections: function (target) {
            return _getSelections(target);
        },
        /**
         * @summary 获得选择的第一个面板对象
         * @name uiAccordion#getSelected
         * @function
         * @returns {Array<uiPanel>} 获得选择的第一个面板对象
         */
        getSelected: function (target) {
            return _getSelected(target);
        },
        /**
         * @summary 根据面板索引获得组件的面板对象
         * @name uiAccordion#getPanel
         * @function
         * @param which {Number} 面板索引
         * @returns {uiPanel|null} 组件的面板对象，若未找到则返回null
         * @example
         * $('#divMenu').uiAccordion("getPanel", 0);
         */
        getPanel: function (target, which) {
            return _getPanel(target, which);
        },
        /**
         * @summary 根据组件面板对象获得的面板索引
         * @name uiAccordion#getPanelIndex
         * @function
         * @param panel {uiPanel} 面板索引
         * @returns {Number} 组件的面板索引，若未找到则返回-1
         * @example
         * $('#divMenu').uiAccordion("getPanelIndex", panel);
         */
        getPanelIndex: function (target, panel) {
            return _getPanelIndex(target, panel);
        },
        /**
         * @summary 选择指定的组件的面板对象
         * @name uiAccordion#select
         * @function
         * @param which {Number} 面板索引
         * @returns {jQuery} 方法调用者
         * @example
         * $('#divMenu').uiAccordion("select", 0);
         */
        select: function (target, which) {
            _select(target, which);
            return target;
        },
        /**
         * @summary 取消选择指定的组件的面板对象
         * @name uiAccordion#unselect
         * @function
         * @param which {Number} 面板索引
         * @returns {jQuery} 方法调用者
         * @example
         * $('#divMenu').uiAccordion("unselect", 0);
         */
        unselect: function (target, which) {
            _unselect(target, which);
            return target;
        },
        /**
         * @summary 为组件添加面板对象
         * @name uiAccordion#add
         * @function
         * @param options {Object} 面板配置参数
         * @returns {jQuery} 方法调用者
         */
        add: function (target, options) {
            _add(target, options);
            return target;
        },
        /**
         * @summary 移除指定的组件的面板对象
         * @name uiAccordion#remove
         * @function
         * @param which {Number} 面板索引
         * @returns {jQuery} 方法调用者
         * @example
         * $('#divMenu').uiAccordion("remove", 0);
         */
        remove: function (target, which) {
            _remove(target, which);
            return target;
        }
    };

    /**
     * 默认配置
     * @lends uiAccordion.prototype
     */
    $.fn.uiAccordion.defaults = {
        /**
         * @type Number
         * @default 0
         * @summary 组件宽度
         */
        width: 0,
        /**
         * @type Number
         * @default 0
         * @summary 组件高度
         */
        height: 0,
        /**
         * @type Boolean
         * @default false
         * @summary 是否自适应宽高
         */
        autoFit: false,
        /**
         * @type Boolean
         * @default true
         * @summary 是否显示边框
         */
        border: true,
        /**
         * @type Boolean
         * @default false
         * @summary 是否可展开多个面板
         */
        multiple: false,
        /**
         * @type Number
         * @default 0
         * @summary 默认展开的面板索引
         */
        selected: 0,
        /**
         * @summary 在面板展开时触发的方法。
         * @event
         * @name uiAccordion#onSelect
         * @param title {String} 所选面板的标题
         * @param index {Number} 所选面板的索引
         * @default emptyFn
         */
        onSelect: function (title, index) {},
        /**
         * @summary 在面板收缩时触发的方法。
         * @event
         * @name uiAccordion#onUnselect
         * @param title {String} 所选面板的标题
         * @param index {Number} 所选面板的索引
         * @default emptyFn
         */
        onUnselect: function (title, index) {},
        /**
         * @summary 在面板被添加时触发的方法。
         * @event
         * @name uiAccordion#onAdd
         * @param title {String} 所选面板的标题
         * @param index {Number} 所选面板的索引
         * @default emptyFn
         */
        onAdd: function (title, index) {},
        /**
         * 若方法返回false，则移除操作将撤销
         * @summary 在面板被移除前触发的方法。
         * @event
         * @name uiAccordion#onBeforeRemove
         * @param title {String} 所选面板的标题
         * @param index {Number} 所选面板的索引
         * @default emptyFn
         */
        onBeforeRemove: function (title, index) {},
        /**
         * @summary 在面板被移除后触发的方法。
         * @event
         * @name uiAccordion#onRemove
         * @param title {String} 所选面板的标题
         * @param index {Number} 所选面板的索引
         * @default emptyFn
         */
        onRemove: function (title, index) {}
    };
    var _init = function (target) {
        var state = $.data(target[0], _cacheName);
        var options = state.options;
        target.setElemID();
        target.addClass('ui_accordion');
        var targetID = target.getElemID();
        if (options.autoFit) {
            target.autoFit(true, false);
        } else {
            target.autoFit(false);
            if (!isNaN(options.width)) {
                target.outerWidth(options.width);
            } else {
                target.css('width', '');
            }
            if (!isNaN(options.height)) {
                target.outerHeight(options.height);
            } else {
                target.css('height', '');
            }
        }
        if(options.multiple){
            target.css({overflow:'scroll',overflowX:'hidden'});
        }
        state.panels = [];
        target.children('div').each(function (index) {
            var pal = $(this);
            pal.addClass('ui_accordion-panel');
            pal.setIDByParentID(targetID, index);
            var opts = $.extend({}, pal.parseUIConfig(), {
                selected: (pal.attr('selected') ? true : undefined)
            });
            state.panels.push(pal);
            _createPanel(target, pal, opts);
        });

        target.bind('_resize', function (e, force) {
            if (options.autoFit == true || force) {
                target.autoFit(true, false);
                _setSize(target);
            }
            return false;
        });
    }

    var _createPanel = function (target, pal, palOptions) {
        var opts = $.data(target[0], _cacheName).options;
        pal.uiPanel($.extend({}, {
            collapsible: true,
            width: target.width(),
            height: 27,
            border: false,
            minimizable: false,
            maximizable: false,
            closable: false,
            collapsed: true
        }, palOptions, {
            onBeforeExpand: function () {
                if (!opts.multiple) {
                    var all = $.grep(_getSelections(target), function (p) {
                        return p.uiPanel('options').collapsible;
                    });
                    for (var i = 0; i < all.length; i++) {
                        _unselect(target, _getPanelIndex(target, all[i]));
                    }
                }
                var header = $(this).uiPanel('header');
                header.addClass('ui_accordion-header-selected');
                var btnColl_icon = $.getByParentID(palID, $.uiTemplate.panel.btnColl_Icon);
                btnColl_icon.removeClass('icon_pal_exp').addClass('icon_pal_col').attr('title', '收缩');
            },
            onExpand: function () {
                opts.onSelect.call(target, $(this).uiPanel('options').title, _getPanelIndex(target, this));
            },
            onBeforeCollapse: function () {
                var header = $(this).uiPanel('header');
                header.removeClass('ui_accordion-header-selected');
                var btnColl_icon = $.getByParentID(palID, $.uiTemplate.panel.btnColl_Icon);
                btnColl_icon.removeClass('icon_pal_col').addClass('icon_pal_exp').attr('title', '展开');
            },
            onCollapse: function () {
                opts.onUnselect.call(target, $(this).uiPanel('options').title, _getPanelIndex(target, this));
            }
        }));
        var palOpts = pal.uiPanel('options');
        if (palOpts.collapsible) {
            var palID = pal.getElemID();
            var header = pal.uiPanel('header');
            header.css('cursor', 'pointer');
            var btnColl = $.getByParentID(palID, $.uiTemplate.panel.btnColl);
            btnColl.unbind('click.panel').bind('click.accordion', function () {
                if (palOpts.collapsed) {
                    pal.uiPanel('expand', false);
                } else {
                    if (opts.multiple) {
                        pal.uiPanel('collapse', false);
                    } else {
                        if (!header.hasClass('ui_accordion-header-selected')) {
                            pal.uiPanel('collapse', false);
                        }
                    }
                }
                return false;
            });
        }
    }

    var _setSize = function (target) {
        var state = $.data(target[0], _cacheName);
        var panels = state.panels;
        var headerHeight = 0;
        var bodyHeight = 0;
        var headers = target.find('>div.ui_panel>div.ui_panel_header');
        if (headers.length) {
            headerHeight = $(headers[0]).outerHeight();
        }
        bodyHeight = target.height() - headerHeight * headers.length;
        _resize(true, bodyHeight - _resize(false));

        function _resize(collapsible, height) {
            var totalHeight = 0;
            for (var i = 0; i < panels.length; i++) {
                var p = panels[i];
                var h = p.uiPanel('header').outerHeight(headerHeight);
                if (p.uiPanel('options').collapsible == collapsible) {
                    var pheight = isNaN(height) ? undefined : (height + headerHeight * h.length);
                    p.uiPanel('resize', {
                        width: state.options.multiple?target[0].clientWidth:target.width(),
                        height: (collapsible ? pheight : undefined)
                    });
                    totalHeight += p.uiPanel('panel').outerHeight() - headerHeight;
                }
            }
            return totalHeight;
        }
    }
    var _findBy = function (target, property, value, all) {
        var panels = $.data(target[0], _cacheName).panels;
        var pp = [];
        for (var i = 0; i < panels.length; i++) {
            var p = panels[i];
            if (property) {
                if (p.uiPanel('options')[property] == value) {
                    pp.push(p);
                }
            } else {
                if (p[0] == $(value)[0]) {
                    return i;
                }
            }
        }
        if (property) {
            return all ? pp : (pp.length ? pp[0] : null);
        } else {
            return -1;
        }
    }

    var _getSelections = function (target) {
        return _findBy(target, 'collapsed', false, true);
    }

    var _getSelected = function (target) {
        var pp = _getSelections(target);
        return pp.length ? pp[0] : null;
    }

    /**
     * get panel index, start with 0
     */
    var _getPanelIndex = function (target, panel) {
        return _findBy(target, null, panel);
    }

    /**
     * get the specified panel.
     */
    var _getPanel = function (target, which) {
        var panels = $.data(target[0], _cacheName).panels;
        if (typeof which == 'number') {
            if (which < 0 || which >= panels.length) {
                return null;
            } else {
                return panels[which];
            }
        }
        return _findBy(target, 'title', which);
    }

    var _setProperties = function (target) {
        var opts = $.data(target[0], _cacheName).options;
        if (opts.border) {
            target.removeClass('ui_accordion-noborder');
        } else {
            target.addClass('ui_accordion-noborder');
        }
    }

    /**
     * select and set the specified panel active
     */
    var _select = function (target, which) {
        var p = _getPanel(target, which);
        if (!p) {
            return
        }
        p.uiPanel('expand', false);
    }

    var _unselect = function (target, which) {
        var pal = _getPanel(target, which);
        if (!pal) {
            return
        }
        pal.uiPanel('collapse', false);
    }

    var _doFirstSelect = function (target) {
        var opts = $.data(target[0], _cacheName).options;
        var pal = _findBy(target, 'selected', true);
        if (pal) {
            _selectP(_getPanelIndex(target, pal));
        } else {
            _selectP(opts.selected);
        }

        function _selectP(index) {
            _select(target, index);
        }
    }

    var _add = function (target, options) {
        var state = $.data(target[0], _cacheName);
        var opts = state.options;
        var panels = state.panels;
        if (options.selected == undefined) options.selected = true;

        var pal = $('<div></div>').appendTo(target);
        panels.push(pal);
        _createPanel(target, pal, options);
        _setSize(target);

        opts.onAdd.call(target, options.title, panels.length - 1);

        if (options.selected) {
            _select(target, panels.length - 1);
        }
    }

    var _remove = function (target, which) {
        var state = $.data(target[0], _cacheName);
        var opts = state.options;
        var panels = state.panels;

        var panel = _getPanel(target, which);
        var title = panel.uiPanel('options').title;
        var index = _getPanelIndex(target, panel);

        if (!panel) {
            return
        }
        if (opts.onBeforeRemove.call(target, title, index) == false) {
            return
        }
        panels.splice(index, 1);
        panel.uiPanel('destroy');
        if (panels.length) {
            _setSize(target);
            var curr = _getSelected(target);
            if (!curr) {
                _select(target, 0);
            }
        }
        opts.onRemove.call(target, title, index);
    }
})(jQuery);